
package com.insigma.business.qrcode.welfare._provider.impl;


import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.insigma.business.qrcode.common.template.BasePagingResponse;
import com.insigma.business.qrcode.common.util.BizCheckUtil;
import com.insigma.business.qrcode.common.util.DateUtils;
import com.insigma.business.qrcode.common.util.ResponseUtils;
import com.insigma.business.qrcode.common.vo.BaseDeleteRequest;
import com.insigma.business.qrcode.common.vo.BaseResponse;
import com.insigma.business.qrcode.soldier.dto.SimpleApiRequest;
import com.insigma.business.qrcode.soldier.dto.gov.BaseProviderImpl;
import com.insigma.business.qrcode.common.template.area.ScenarioCodeEnum;
import com.insigma.business.qrcode.common.template.area.ServiceCallback;
import com.insigma.business.qrcode.soldier.entity.DataStatsCDO;
import com.insigma.business.qrcode.soldier.entity.SoldierBasicInfoDO;
import com.insigma.business.qrcode.soldier.entity.WestLakeRecordEntity;
import com.insigma.business.qrcode.soldier.request.BaseGetRequest;
import com.insigma.business.qrcode.soldier.service.SoldierBasicInfoService;
import com.insigma.business.qrcode.soldier.service.ThirdPartyService;
import com.insigma.business.qrcode.soldier.util.MiniCacheUtils;
import com.insigma.business.qrcode.soldier.util.ThreadPoolManager;
import com.insigma.business.qrcode.welfare.dto.*;
import com.insigma.business.qrcode.welfare.entity.ScanCodeRecordDO;
import com.insigma.business.qrcode.welfare.request.ScanCodeRecordInsertRequest;
import com.insigma.business.qrcode.welfare.request.ScanCodeRecordSearchRequest;
import com.insigma.business.qrcode.welfare.request.ScanCodeRecordUpdateRequest;
import com.insigma.business.qrcode.welfare._provider.ScanCodeRecordProvider;
import com.insigma.business.qrcode.welfare.service.ScanCodeRecordService;
import com.insigma.business.qrcode.common.converter.ScanCodeRecordProviderConverter;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.Future;


@Slf4j
@Service
@Component("scanCodeRecordProvider")
public class ScanCodeRecordProviderImpl extends BaseProviderImpl implements ScanCodeRecordProvider {

    @Autowired
    private ScanCodeRecordService scanCodeRecordService;

    @Autowired
    private MiniCacheUtils miniCacheUtils;

    @Autowired
    private ThirdPartyService thirdPartyService;

    @Autowired
    private SoldierBasicInfoService soldierBasicInfoService;


    @Override
    public BasePagingResponse<List<ScanCodeRecordDTO>> searchScanCodeRecord(final ScanCodeRecordSearchRequest searchRequest) {

        final BasePagingResponse<List<ScanCodeRecordDTO>> basePagingResponse = new BasePagingResponse<>();
        serviceTemplate.execute(basePagingResponse, new ServiceCallback() {
            @Override
            public void check() {
                BizCheckUtil.checkNotNull(searchRequest, "查询分页ScanCodeRecord的请求参数不能为空");
            }

            @Override
            public void executeService() {
                final ScanCodeRecordBSearcher scanCodeRecordBSearcher = ScanCodeRecordProviderConverter.convertRequestSO2Searcher(searchRequest);
                final List<ScanCodeRecordDO> scanCodeRecordDOList = scanCodeRecordService.search(scanCodeRecordBSearcher);
                final List<ScanCodeRecordDTO> scanCodeRecordDTOList = ScanCodeRecordProviderConverter.convertResponseDOList2DTOList(scanCodeRecordDOList);
                ResponseUtils.buildSuccessPagingResponse(basePagingResponse, scanCodeRecordDTOList, searchRequest, scanCodeRecordBSearcher.getTotalCount());
            }

            @Override
            public ScenarioCodeEnum getScenarioEnum() {
                return ScenarioCodeEnum.SCAN_CODE_RECORD_SEARCH;
            }
        });

        return basePagingResponse;
    }

    @Override
    public BasePagingResponse<List<ScanCodeRecordDTO>> searchHospitalRecord(ScanCodeRecordSearchRequest searchRequest) {

        if ("萧山医院".equals(searchRequest.getBizName())) {
            searchRequest.setBizName("xsyy");
        }

        final ScanCodeRecordBSearcher scanCodeRecordBSearcher = ScanCodeRecordProviderConverter.convertRequestSO2Searcher(searchRequest);
        final List<ScanCodeRecordDO> scanCodeRecordDOList = scanCodeRecordService.searchHospitalRecord(scanCodeRecordBSearcher);
        final List<ScanCodeRecordDTO> scanCodeRecordDTOList = ScanCodeRecordProviderConverter.convertResponseDOList2DTOList(scanCodeRecordDOList);
        if (!CollectionUtils.isEmpty(scanCodeRecordDTOList)) {
            for (ScanCodeRecordDTO scanCodeRecordDTO : scanCodeRecordDTOList) {
                if ("xsyy".equals(scanCodeRecordDTO.getBizName())) {
                    scanCodeRecordDTO.setBizName("萧山医院");
                }
            }
        }
        return ResponseUtils.buildSuccessPagingResponse(scanCodeRecordDTOList, scanCodeRecordBSearcher);
    }

    @Override
    public BasePagingResponse<List<ScanCodeRecordDTO>> searchMyRecord(ScanCodeRecordSearchRequest searchRequest) {

        BizCheckUtil.checkNotNull(searchRequest, "查询分页ScanCodeRecord的请求参数不能为空");
        BizCheckUtil.checkNotNull(searchRequest.getSoldierId(), "soldierId请求参数不能为空");

        final ScanCodeRecordBSearcher scanCodeRecordBSearcher = ScanCodeRecordProviderConverter.convertRequestSO2Searcher(searchRequest);
        scanCodeRecordBSearcher.setType(RecordTypeEnum.MERCHANT.name());

        if (Strings.isNotBlank(searchRequest.getMonth())) {
            DateTime parse = DateUtil.parse(searchRequest.getMonth(), "yyyy-MM");
            Date date = parse.toJdkDate();
            DateTime monthStart = DateUtil.beginOfMonth(date);
            DateTime monthEnd = DateUtil.endOfMonth(date);
            scanCodeRecordBSearcher.setStartTime(monthStart.toJdkDate());
            scanCodeRecordBSearcher.setEndTime(monthEnd.toJdkDate());
        }

        final List<ScanCodeRecordDO> scanCodeRecordDOList = scanCodeRecordService.search(scanCodeRecordBSearcher);
        final List<ScanCodeRecordDTO> scanCodeRecordDTOList = ScanCodeRecordProviderConverter.convertResponseDOList2DTOList(scanCodeRecordDOList);
        if (!CollectionUtils.isEmpty(scanCodeRecordDTOList)) {
            for (ScanCodeRecordDTO scanCodeRecordDTO : scanCodeRecordDTOList) {
                if (Strings.isBlank(scanCodeRecordDTO.getBizName())) {
                    String cachedMerchantNameById = miniCacheUtils.getCachedMerchantNameById(scanCodeRecordDTO.getBizId());
                    String logo = miniCacheUtils.getCachedMerchantLogById(scanCodeRecordDTO.getBizId());
                    scanCodeRecordDTO.setBizName(cachedMerchantNameById);
                    scanCodeRecordDTO.setBizLogo(logo);
                }
            }
        }

        return ResponseUtils.buildSuccessPagingResponse(scanCodeRecordDTOList, scanCodeRecordBSearcher);
    }


    @Override
    public BaseResponse<ScanCodeRecordDTO> getScanCodeRecord(final BaseGetRequest baseGetRequest) {

        final BaseResponse<ScanCodeRecordDTO> baseResponse = new BaseResponse<>();
        serviceTemplate.execute(baseResponse, new ServiceCallback() {
            @Override
            public void check() {
                BizCheckUtil.checkNotNull(baseGetRequest, "获取单条ScanCodeRecord的请求参数不能为空");
                BizCheckUtil.checkNotBlank((String) baseGetRequest.getId(), "id不能为空");
            }

            @Override
            public void executeService() {
                final ScanCodeRecordDO scanCodeRecordDO = scanCodeRecordService.get((String) baseGetRequest.getId());
                final ScanCodeRecordDTO remoteObj = ScanCodeRecordProviderConverter.convertResponseDO2DTO(scanCodeRecordDO);
                ResponseUtils.setupSuccessResponse(baseResponse, remoteObj);
            }

            @Override
            public ScenarioCodeEnum getScenarioEnum() {
                return ScenarioCodeEnum.SCAN_CODE_RECORD_GET;
            }
        });
        return baseResponse;
    }

    @Override
    public BaseResponse<ScenicSpotStatsDTO> getScenicSpotStats(SimpleApiRequest request) {


        ScenicSpotStatsDTO dto = new ScenicSpotStatsDTO();
        dto.setSpotNum(17);
        Integer consumeNum = scanCodeRecordService.countByTypeAndBizName(RecordTypeEnum.SCENIC_SPOT.name(), null);
        dto.setConsumeNum(consumeNum);

        Integer consumePersonNum = scanCodeRecordService.groupCountByTypeAndBizName(RecordTypeEnum.SCENIC_SPOT.name(), null);
        dto.setConsumePersonNum(consumePersonNum);
        dto.setDiscountNum(consumeNum);

        LinkedHashMap<String, Integer> map = new LinkedHashMap<>();
        List<String> list = DateUtils.listNearDateMonthWithThisMonyhyyyyMM(6);
        Collections.reverse(list);
        for (String time : list) {
            Integer cc = scanCodeRecordService.countByTypeAndBizNameAndBizTime(RecordTypeEnum.SCENIC_SPOT.name(), null, time);
            map.put(time, cc);
        }
        dto.setSpotTimeTrendMap(map);
        return ResponseUtils.buildSuccessResponse(dto);
    }

    @Override
    public BaseResponse<HospitalStatsDTO> getHospitalStats(SimpleApiRequest request) {

        String adminAreaCode = "330100000000";
        HospitalStatsDTO dto = new HospitalStatsDTO();

        Future<?> submit = ThreadPoolManager.getInstance().submit(new Runnable() {
            @Override
            public void run() {
                Integer hhyyNum = scanCodeRecordService.countByBizNameOfHospital(adminAreaCode, "红会医院");
                dto.setHhyyNum(hhyyNum);
                Integer integer = scanCodeRecordService.countByBizNameOfHospital(adminAreaCode, "xsyy");
                dto.setXsyyNum(integer);
                dto.setSyfyyNum(3005);
            }
        });

        LinkedHashMap<String, Integer> map = new LinkedHashMap<>();
        List<String> list = DateUtils.listNearDateMonthWithThisMonyhyyyyMM(6);
        Collections.reverse(list);
        for (String time : list) {
            Integer cc = scanCodeRecordService.countHospitalByBizTime(time);
            map.put(time, cc);
        }
        dto.setHospitalTimeTrendMap(map);

        Future<?> submit1 = ThreadPoolManager.getInstance().submit(new Runnable() {
            @Override
            public void run() {
                LinkedHashMap<String, Integer> hospitalAreaMap = new LinkedHashMap<>();
                List<DataStatsCDO> areaMap = scanCodeRecordService.groupHospital(adminAreaCode);
                for (DataStatsCDO dataStatsCDO : areaMap) {
                    hospitalAreaMap.put(dataStatsCDO.getItemCNName(), dataStatsCDO.getItemCount());
                }
                dto.setHospitalAreaMap(sortMap(hospitalAreaMap));
            }
        });

        try {
            submit.get();
            submit1.get();
        } catch (Exception e) {
            log.error("e:{}", e);
        }
        dto.setHospitalNum(dto.getHhyyNum() + dto.getSyfyyNum() + dto.getXsyyNum());
        return ResponseUtils.buildSuccessResponse(dto);
    }

    public static LinkedHashMap<String, Integer> sortMap(Map<String, Integer> map) {
        List<Map.Entry<String, Integer>> entryList = new ArrayList<>(map.entrySet());
        Collections.sort(entryList, new Comparator<Map.Entry<String, Integer>>() {
            @Override
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                return o2.getValue() - o1.getValue();
            }
        });
        LinkedHashMap<String, Integer> linkedHashMap = new LinkedHashMap<String, Integer>();
        for (Map.Entry<String, Integer> e : entryList) {
            linkedHashMap.put(e.getKey(), e.getValue());
        }
        return linkedHashMap;
    }


    @Override
    public BaseResponse<String> insertScanCodeRecord(final ScanCodeRecordInsertRequest insertRequest) {

        final BaseResponse<String> baseResponse = new BaseResponse<>();
        serviceTemplate.execute(transactionTemplate, baseResponse, new ServiceCallback() {
            @Override
            public void check() {
                BizCheckUtil.checkNotNull(insertRequest, "新增ScanCodeRecord的请求参数不能为空");
            }

            @Override
            public void executeService() {
                final ScanCodeRecordDO scanCodeRecordDO = ScanCodeRecordProviderConverter.convertRequestIO2DO(insertRequest);
                scanCodeRecordService.insert(scanCodeRecordDO);
                ResponseUtils.setupSuccessResponse(baseResponse, scanCodeRecordDO.getId());
            }

            @Override
            public ScenarioCodeEnum getScenarioEnum() {
                return ScenarioCodeEnum.SCAN_CODE_RECORD_INSERT;
            }
        });
        return baseResponse;
    }


    @Override
    public BaseResponse<Integer> updateScanCodeRecord(final ScanCodeRecordUpdateRequest updateRequest) {

        final BaseResponse<Integer> baseResponse = new BaseResponse<>();
        serviceTemplate.execute(transactionTemplate, baseResponse, new ServiceCallback() {
            @Override
            public void check() {
                BizCheckUtil.checkNotNull(updateRequest, "修改ScanCodeRecord的请求参数不能为空");
                BizCheckUtil.checkNotBlank(updateRequest.getId(), "id不能为空");
                BizCheckUtil.checkNotBlank(updateRequest.getModifierId(), "操作人不能为空");
                BizCheckUtil.checkNotBlank(updateRequest.getModifierType(), "操作人类型不能为空");
            }

            @Override
            public void executeService() {
                ScanCodeRecordDO scanCodeRecordDO = ScanCodeRecordProviderConverter.convertRequestUO2DO(updateRequest);
                Integer affectRowNum = scanCodeRecordService.update(scanCodeRecordDO);
                ResponseUtils.setupSuccessResponse(baseResponse, affectRowNum);
            }

            @Override
            public ScenarioCodeEnum getScenarioEnum() {
                return ScenarioCodeEnum.SCAN_CODE_RECORD_UPDATE;
            }
        });
        return baseResponse;
    }


    @Override
    public BaseResponse<Integer> deleteScanCodeRecord(final BaseDeleteRequest deleteRequest) {

        final BaseResponse<Integer> baseResponse = new BaseResponse<>();
        serviceTemplate.execute(transactionTemplate, baseResponse, new ServiceCallback() {
            @Override
            public void check() {
                BizCheckUtil.checkNotNull(deleteRequest, "逻辑删除ScanCodeRecord的请求参数不能为空");
                BizCheckUtil.checkNotBlank((String) deleteRequest.getId(), "id不能为空");
                BizCheckUtil.checkNotBlank(deleteRequest.getModifierType(), "操作人类型不能为空");
                BizCheckUtil.checkNotBlank((String) deleteRequest.getModifierId(), "操作人不能为空");
            }

            @Override
            public void executeService() {
                final Integer affectRowNum = scanCodeRecordService.delete((String) deleteRequest.getId(), deleteRequest.getModifierType(), (String) deleteRequest.getModifierId());
                ResponseUtils.setupSuccessResponse(baseResponse, affectRowNum);
            }

            @Override
            public ScenarioCodeEnum getScenarioEnum() {
                return ScenarioCodeEnum.SCAN_CODE_RECORD_DELETE_LOGICALLY;
            }
        });
        return baseResponse;
    }

    @Override
    public BaseResponse<Integer> addWestLakeRecord(String startTime, String endTime) {

        BizCheckUtil.checkNotNull(startTime);
        BizCheckUtil.checkNotNull(endTime);
        List<WestLakeRecordEntity> westLakeRecordEntities = thirdPartyService.queryWestLakeRecord(startTime, endTime);
        if (!CollectionUtils.isEmpty(westLakeRecordEntities)) {
            for (WestLakeRecordEntity westLakeRecordEntity : westLakeRecordEntities) {

                ScanCodeRecordDO scanCodeRecordDO = new ScanCodeRecordDO();
                scanCodeRecordDO.setName(westLakeRecordEntity.getRealName());
                scanCodeRecordDO.setIdCardNo(westLakeRecordEntity.getIdCardNo());
                SoldierBasicInfoDO byIdCardNo = soldierBasicInfoService.getByIdCardNo(westLakeRecordEntity.getIdCardNo());
                if (byIdCardNo != null) {
                    scanCodeRecordDO.setSoldierId(byIdCardNo.getIdCardNo());
                }
                scanCodeRecordDO.setType(RecordTypeEnum.SCENIC_SPOT.name());
                scanCodeRecordDO.setBizType(RecordTypeEnum.SCENIC_SPOT.name());
                scanCodeRecordDO.setBizId(String.valueOf(westLakeRecordEntity.getId()));
                scanCodeRecordDO.setBizName("西湖景区");
                scanCodeRecordDO.setAddress(westLakeRecordEntity.getAttraction());
                scanCodeRecordDO.setBizDatetime(westLakeRecordEntity.getCreateTime());
                scanCodeRecordService.insert(scanCodeRecordDO);
            }
        }

        return ResponseUtils.buildSuccessResponse(0);
    }
}
